﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarbonExchange.AmeeQuery;
using CarbonExchange.Dal;

namespace CarbonExchange.Bll
{
    public class AuditFactory : FactoryBase<Audit>
    {

        public AuditFactory() : base() { }

        public AuditFactory(IAmeeCommand ameeCommand) : base(ameeCommand) { }

        public AuditFactory(Context dalContext) : base(dalContext) { }

        public AuditFactory(IAmeeCommand ameeCommand, Context dalContext) : base(ameeCommand, dalContext) { }

        protected override void MarkItemForDeletion(Audit item)
        {
            var tmp = item.Convert(DalContext, AmeeCommand);
            tmp.Deleted = true;
        }

        protected override void Validate(IQueryable<Audit> items, CarbonExchange.Bll.Exceptions.ValidationException e)
        {
            items.Validate(e, DalContext);
        }

        protected override void PopulateDataChanges(Audit item, object dataItem)
        {
            var tmp = dataItem as Dal.Audit;
            if (item.Id == 0)
            {
                item.Id = tmp.Id;
                item.Created = tmp.Created.ToLocalTime();
                item.AuditKey = tmp.AuditKey;
            }
        }

        protected override object GetDataItemForUpdate(Audit item)
        {
            return item.Convert(DalContext, AmeeCommand);
        }

        private IQueryable<Dal.Audit> GetSelection()
        {
            return DalContext.Audits.Where(x => !x.Deleted).OrderByDescending(x => x.StartDate);
        }

        public Audit GetById(int id)
        {
            return GetSelection().Where(x => x.Id == id).SingleOrDefault().Convert();
        }

        public Audit GetByIdAndUserId(int id, int userId)
        {
            return GetSelection().Where(x => x.Id == id && x.UserId == userId).SingleOrDefault().Convert();
        }

        public IQueryable<Audit> GetAllByUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId).Convert();
        }

        public IQueryable<Audit> GetAllCompletedByUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId && x.Completed).Convert();
        }

        public Audit GetLatestCompletedByUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId && x.Completed).FirstOrDefault().Convert();
        }

        public Audit GetCurrentForUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId && x.Completed == false).FirstOrDefault().Convert();
        }

        public Audit GetLatestForUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId).FirstOrDefault().Convert();
        }

        /// <summary>
        /// Total amount of Co2 per year
        /// </summary>
        /// <returns></returns>
        public int GetTotalCarbonAudited()
        {
            return Convert.ToInt32(GetSelection().Where(audit => audit.Completed).Sum(audit => audit.Answers.Sum(answers => answers.AnswerItems.Sum(answerItem => answerItem.Footprint ?? 0)))) * 12;
        }
    }

    public static class AduitConverter
    {
        public static Audit Convert(this Dal.Audit source)
        {
            return ConvertItem(source);
        }

        public static IQueryable<Audit> Convert(this IQueryable<Dal.Audit> source)
        {
            return source.Select(x => ConvertItem(x));
        }

        private static Audit ConvertItem(Dal.Audit dataItem)
        {
            if (dataItem != null)
            {
                return new Audit()
                {
                    Id = dataItem.Id,
                    AuditKey = dataItem.AuditKey,
                    Created = DateTime.SpecifyKind(dataItem.Created, DateTimeKind.Utc).ToLocalTime(),
                    EndDate = DateTime.SpecifyKind(dataItem.EndDate, DateTimeKind.Utc).ToLocalTime(),
                    StartDate = DateTime.SpecifyKind(dataItem.StartDate, DateTimeKind.Utc).ToLocalTime(),
                    UserId = dataItem.UserId,
                    CountryId = dataItem.CountryId,
                    State = dataItem.State,
                    PeopleInHousehold = dataItem.PeopleInHousehold,
                    Completed = dataItem.Completed
                };
            }
            else
            {
                return null;
            }
        }

        public static Dal.Audit Convert(this Audit source, Dal.Context context, IAmeeCommand command)
        {
            return ConvertItem(source, context, command);
        }

        private static Dal.Audit ConvertItem(Audit item, Dal.Context context, IAmeeCommand command)
        {
            Dal.Audit dataItem = null;
            if(item != null)
            {
                if (item.Id > 0)
                {
                    dataItem = context.Audits.Where(x => x.Id == item.Id).Single();
                }
                else
                {
                    dataItem = new CarbonExchange.Dal.Audit();
                    context.Audits.InsertOnSubmit(dataItem);
                    dataItem.Created = DateTime.UtcNow;
                    AmeeProfileFactory ameeProfileFactory = new AmeeProfileFactory(command);
                    AmeeProfile profile = new AmeeProfile();

                    profile.Country = item.Country != null ? item.Country.Name : "";
                    profile.PeopleInHoushold = item.PeopleInHousehold;
                    profile.StartDate = item.StartDate;
                    profile.State = item.State;

                    ameeProfileFactory.Save(profile);
                    item.AuditKey = profile.Id;
                }
                dataItem.AuditKey = item.AuditKey;
                dataItem.EndDate = item.EndDate.ToUniversalTime();
                dataItem.StartDate = item.StartDate.ToUniversalTime();
                dataItem.UserId = item.UserId;
                dataItem.PeopleInHousehold = item.PeopleInHousehold;
                dataItem.CountryId = item.CountryId;
                dataItem.State = item.State;
                dataItem.Completed = item.Completed;
            }
            return dataItem;
        }

        public static void Validate(this IQueryable<Audit> items, Exceptions.ValidationException e, Dal.Context context)
        {
            foreach(var item in items)
            {
                ValidateItem(item, e, context);
            }
        }

        private static void ValidateItem(Audit item, Exceptions.ValidationException e, Dal.Context context)
        {
            if (!(item.UserId > 0))
            {
                e.Add("Must Specify User Id");
            }
            if (item.StartDate == DateTime.MinValue)
            {
                e.Add("Must Specify Start Date");
            }
            if (item.EndDate == DateTime.MinValue)
            {
                e.Add("Must Specify End Date");
            }
            //check there are no duplicates
            /*var duplicates = context.Audits.Where(x => x.UserId == item.UserId && x.Id != item.Id);
            duplicates = duplicates.Where(x => (x.StartDate <= item.StartDate.ToUniversalTime() && x.EndDate > item.StartDate.ToUniversalTime() || x.StartDate < item.EndDate.ToUniversalTime() && x.EndDate >= item.EndDate.ToUniversalTime()));
            if (duplicates.Count() > 0)
            {
                e.Add("Start Date and End Date Overlaps");
            }*/
        }
    }
}
